package com.dnjn.happiness.biz.modbus;

import com.dnjn.happiness.biz.enums.DataType;
import com.dnjn.happiness.common.config.AppConfig;
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;
import com.intelligt.modbus.jlibmodbus.exception.ModbusNumberException;
import com.intelligt.modbus.jlibmodbus.exception.ModbusProtocolException;
import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;
import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;
import com.intelligt.modbus.jlibmodbus.msg.request.ReadHoldingRegistersRequest;
import com.intelligt.modbus.jlibmodbus.msg.response.ReadHoldingRegistersResponse;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Slf4j
@Component
public class ModbusMasterHelper {

    @Autowired
    private AppConfig appConfig;

    public ModbusMaster getModbusMaster() throws UnknownHostException {
        return getModbusMaster(appConfig.getModbus().getHost(), appConfig.getModbus().getPort());//todo
    }

    public ModbusMaster getModbusMaster(String host, Integer port) throws UnknownHostException {
        TcpParameters parameters = new TcpParameters();
        InetAddress address = InetAddress.getByName(host);
        //parameters.setHost(InetAddress.getLocalHost());
        parameters.setHost(address);
        parameters.setKeepAlive(false);
        parameters.setPort(port); //502
        ModbusMaster master = ModbusMasterFactory.createModbusMasterTCP(parameters);
        Modbus.setAutoIncrementTransactionId(true);
        return master;
    }


    public Number readHoldingRegister(int slaveId, final int startAddress, DataType dataType) {
        ModbusMaster master = null;
        try {
            master = getModbusMaster();
            if (!master.isConnected()) {
                master.connect();
            }
            /*
            int[] values = master.readHoldingRegisters(slaveId, offset, dataType.getQuantity());
            int offsetT = offset;
            for (int value : values) {
                log.info("address {}, value {}", offsetT++, value);
            }*/
            /**/

            ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest();
            request.setServerAddress(slaveId);
            request.setStartAddress(startAddress);
            request.setTransactionId(0);
            request.setQuantity(dataType.getQuantity());//?

            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.processRequest(request);
            ModbusHoldingRegisters registers = response.getHoldingRegisters();

            Number number;
            byte aByte = registers.getBytes()[0];
            byte[] bytes = toPrim(aByte);
            switch (dataType) {
                case FLOAT32:
                    number = registers.getFloat32At(0);
                    break;
                case FLOAT64:
                    number = registers.getFloat64At(0);
                    break;
                case INT8:
                    number = registers.getInt8At(0);
                    break;
                case INT16:
                    number = registers.getInt16At(0);
                    break;
                case INT32:
                    number = registers.getInt32At(0);
                    break;
                case INT64:
                    number = registers.getInt64At(0);//?
                    break;
                case BIT0:
                    //number = registers.getBytes()[0];
                    number = bytes[7];
                    break;
                case BIT1:
                    //number = registers.getBytes()[1];
                    number = bytes[6];
                    break;
                case BIT2:
                    //number = registers.getBytes()[2];
                    number = bytes[5];
                    break;
                case BIT3:
                    //number = registers.getBytes()[3];
                    number = bytes[4];
                    break;
                case BIT4:
                    //number = registers.getBytes()[4];
                    number = bytes[3];
                    break;
                case BIT5:
                    //number = registers.getBytes()[5];
                    number = bytes[2];
                    break;
                case BIT6:
                    //number = registers.getBytes()[6];
                    number = bytes[1];
                    break;
                case BIT7:
                    //number = registers.getBytes()[7];
                    number = bytes[0];
                    break;
                default:
                    throw new IllegalArgumentException("dataType： " + dataType.name());
            }
            return number;

        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            try {
                if (null != master && master.isConnected()) {
                    master.disconnect();
                }
            } catch (ModbusIOException e) {
                log.error(e.getMessage());
            }
        }
        return null;
    }


    /*
     * 每个值代表bit,8个bit.bit7->bit0
     * 包含8个bit数组，bit7->bit0
     * 顺序bit7->bit0
     * */
   /* public byte[] byteToBitOfArray(byte b){
        byte[] temp = new byte[8];
        for (int i = 7; i >= 0; i--) {
            temp[i] = (byte) ((b>>1)&1);
        }
        return temp;
    }*/

    /*
     * Byte[] 转 byte[]
     * */

    public byte[] toPrim(byte b) {
        byte[] temp = new byte[8];
        for (int i = 7; i >= 0; i--) {
            temp[i] = (byte) (b & 1);
            b = (byte) (b >> 1);
        }
        return temp;
    }

    public static void main(String[] args) throws Exception {

        String host = "192.168.0.10";
        int port = 502;
        int slaveId = 1;
        int startAddress = 22;
        int quantity = 8;
        DataType dataType = DataType.INT16;
        ModbusMasterHelper helper = new ModbusMasterHelper();
        ModbusMaster master = helper.getModbusMaster(host, port);
        if (!master.isConnected()) {
            master.connect();
        }
        ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest();
        request.setServerAddress(slaveId);

        request.setTransactionId(0);
        request.setQuantity(quantity);//?

//        readHoldingRegister(startAddress, master, request);
//        readHoldingRegister(23, master, request);
//        readHoldingRegister(24, master, request);
//        readHoldingRegister(25, master, request);
//        readHoldingRegister(26, master, request);


        startAddress = 12340;
        request.setStartAddress(startAddress);

        ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.processRequest(request);
        ModbusHoldingRegisters registers = response.getHoldingRegisters();
//        int rdata = registers.getInt16At(0);


        double rdata = registers.getFloat32At(0);


    }

    private static void readHoldingRegister(int startAddress, ModbusMaster master,
                                            ReadHoldingRegistersRequest request) throws ModbusNumberException, ModbusProtocolException, ModbusIOException {
        request.setStartAddress(startAddress);

        ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.processRequest(request);
        ModbusHoldingRegisters registers = response.getHoldingRegisters();
        int rdata = registers.getInt16At(0);
    }
}
